#' Load in data from 10X
#'
#' Enables easy loading of sparse data matrices provided by 10X genomics.
#'
#' @param data.dir Directory containing the matrix.mtx, genes.tsv (or features.tsv), and barcodes.tsv
#' files provided by 10X. A vector or named vector can be given in order to load
#' several data directories. If a named vector is given, the cell barcode names
#' will be prefixed with the name.
#' @param gene.column Specify which column of genes.tsv or features.tsv to use for gene names; default is 2
#' @param cell.column Specify which column of barcodes.tsv to use for cell names; default is 1
#' @param unique.features Make feature names unique (default TRUE)
#' @param strip.suffix Remove trailing "-1" if present in all cell barcodes.
#'
#' @return If features.csv indicates the data has multiple data types, a list
#'   containing a sparse matrix of the data from each type will be returned.
#'   Otherwise a sparse matrix containing the expression data will be returned.
#'
#' @importFrom Matrix readMM
#' @importFrom utils read.delim
#'
#' @export
#' @concept preprocessing
#'
#' @examples
#' \dontrun{
#' # For output from CellRanger < 3.0
#' data_dir <- 'path/to/data/directory'
#' list.files(data_dir) # Should show barcodes.tsv, genes.tsv, and matrix.mtx
#' expression_matrix <- Read10X(data.dir = data_dir)
#' seurat_object = CreateSeuratObject(counts = expression_matrix)
#'
#' # For output from CellRanger >= 3.0 with multiple data types
#' data_dir <- 'path/to/data/directory'
#' list.files(data_dir) # Should show barcodes.tsv.gz, features.tsv.gz, and matrix.mtx.gz
#' data <- Read10X(data.dir = data_dir)
#' seurat_object = CreateSeuratObject(counts = data$`Gene Expression`)
#' seurat_object[['Protein']] = CreateAssayObject(counts = data$`Antibody Capture`)
#' }
#'
Read10X <- function(
  data.dir,
  gene.column = 2,
  cell.column = 1,
  unique.features = TRUE,
  strip.suffix = FALSE
) {
  full.data <- list()
  for (i in seq_along(along.with = data.dir)) {
    run <- data.dir[i]

    #如果文件夹不存在
    if (!dir.exists(paths = run)) {
      stop("Directory provided does not exist")
    }

    # 几个稀疏矩阵的文件
    barcode.loc <- file.path(run, 'barcodes.tsv')
    gene.loc <- file.path(run, 'genes.tsv')
    features.loc <- file.path(run, 'features.tsv.gz')
    matrix.loc <- file.path(run, 'matrix.mtx')
    # Flag to indicate if this data is from CellRanger >= 3.0
    pre_ver_3 <- file.exists(gene.loc)
    if (!pre_ver_3) {
      addgz <- function(s) {
        return(paste0(s, ".gz"))
      }
      barcode.loc <- addgz(s = barcode.loc)
      matrix.loc <- addgz(s = matrix.loc)
    }

    # 如果文件不存在
    if (!file.exists(barcode.loc)) {
      stop("Barcode file missing. Expecting ", basename(path = barcode.loc))
    }
    if (!pre_ver_3 && !file.exists(features.loc) ) {
      stop("Gene name or features file missing. Expecting ", basename(path = features.loc))
    }
    if (!file.exists(matrix.loc)) {
      stop("Expression matrix file missing. Expecting ", basename(path = matrix.loc))
    }

    #############
    #1. 读入稀疏矩阵
    data <- readMM(file = matrix.loc)

    #############
    #2. 读入cb
    cell.barcodes <- read.table(file = barcode.loc, header = FALSE, sep = '\t', row.names = NULL)
    if (ncol(x = cell.barcodes) > 1) {
      cell.names <- cell.barcodes[, cell.column]
    } else {
      cell.names <- readLines(con = barcode.loc) #读取单列文本为c()
    }

    # 如果全部都是-1结尾，且 strip.suffix =T
    if (all(grepl(pattern = "\\-1$", x = cell.names)) & strip.suffix) {
      cell.names <- as.vector(x = as.character(x = sapply(
        X = cell.names,
        FUN = ExtractField,
        field = 1,
        delim = "-"
      )))
    }

    # 如果传入的字符串路径没有name
    if (is.null(x = names(x = data.dir))) {
      # 如果长度是1，则列名就等于cid
      if (length(x = data.dir) < 2) {
        colnames(x = data) <- cell.names
      } else {
        # 如果长度>=2，则加上 i_ 前缀作为cid
        colnames(x = data) <- paste0(i, "_", cell.names)
      }
    } else {
      # 如果出入的字符串路径有name，则使用该name作为cid前缀
      colnames(x = data) <- paste0(names(x = data.dir)[i], "_", cell.names)
    }


    #############
    #3. 读入基因名字
    feature.names <- read.delim(
      file = ifelse(test = pre_ver_3, yes = gene.loc, no = features.loc), #判断输入文件的版本
      header = FALSE,
      stringsAsFactors = FALSE #防止character变factor
    )

    # 如果有na，则警告
    if (any(is.na(x = feature.names[, gene.column]))) {
      warning(
        'Some features names are NA. Replacing NA names with ID from the opposite column requested',
        call. = FALSE,
        immediate. = TRUE
      )
      na.features <- which(x = is.na(x = feature.names[, gene.column])) #哪些位置是na
      replacement.column <- ifelse(test = gene.column == 2, yes = 1, no = 2) #替换成第一列
      feature.names[na.features, gene.column] <- feature.names[na.features, replacement.column]
    }
    # 如果 feature必须uniq(默认)
    if (unique.features) {
      fcols = ncol(x = feature.names) #总列数
      if (fcols < gene.column) { #如果总列数<指定的基因列编号，则报错
        stop(paste0("gene.column was set to ", gene.column,
                    " but feature.tsv.gz (or genes.tsv) only has ", fcols, " columns.",
                    " Try setting the gene.column argument to a value <= to ", fcols, "."))
      }
      rownames(x = data) <- make.unique(names = feature.names[, gene.column]) #结尾添加.1形式保证uniq
    }

    # In cell ranger 3.0, a third column specifying the type of data was added
    # and we will return each type of data as a separate matrix
    # ranger 3.0 第三列，数据类型，返回为稀疏矩阵
    if (ncol(x = feature.names) > 2) {
      data_types <- factor(x = feature.names$V3)
      lvls <- levels(x = data_types)
      if (length(x = lvls) > 1 && length(x = full.data) == 0) {
        message("10X data contains more than one type and is being returned as a list containing matrices of each type.")
      }
      expr_name <- "Gene Expression"
      if (expr_name %in% lvls) { # Return Gene Expression first
        lvls <- c(expr_name, lvls[-which(x = lvls == expr_name)])
      }
      data <- lapply(
        X = lvls,
        FUN = function(l) {
          return(data[data_types == l, , drop = FALSE])
        }
      )
      names(x = data) <- lvls
    } else{ #如果不超过2列，则直接塞进list
      data <- list(data) 
    }
    full.data[[length(x = full.data) + 1]] <- data #第一项等于 data 这个 list
  }


  # Combine all the data from different directories into one big matrix, note this
  # assumes that all data directories essentially have the same features files
  # 合并矩阵，这假设多个文件都有同样的 feature 文件(行名)
  list_of_data <- list()
  for (j in 1:length(x = full.data[[1]])) { #这是只对第一个元素内的data遍历吗？
    # 也就是只支持一个输入路径，多了在这里忽略掉了。//bug report: https://github.com/satijalab/seurat/issues/5591

    # 没看懂这个合并的啥？
    list_of_data[[j]] <- do.call(cbind, lapply(X = full.data, FUN = `[[`, j)) #按列合并(行名要一样)
    # Fix for Issue #913
    list_of_data[[j]] <- as(object = list_of_data[[j]], Class = "dgCMatrix") #变为稀疏矩阵
  }

  names(x = list_of_data) <- names(x = full.data[[1]])
  
  # If multiple features, will return a list, otherwise
  # a matrix.
  if (length(x = list_of_data) == 1) {
    return(list_of_data[[1]])
  } else {
    return(list_of_data)
  }
}